#include <opencv2/opencv.hpp>
#include <iostream>
#include <eigen3/Eigen/Dense>
#include <time.h>
#include <vector>
using namespace cv;
using namespace std;
typedef struct Node
{
    int x;
    int y;
    double minLength; //min length
    int flag;
    bool colorflag;
} node;
typedef struct LINEM
{
    Point p_a;
    Point p_b;
    int flag;
} linem;
linem lin[3];
Point p[4];
Mat image;
void create()
{
    srand((unsigned int)time(NULL));
    image = Mat(400, 600, CV_8UC3, Scalar(255, 255, 255));
    image.at<Vec3b>(200, 300)[0] = 0;
    p[1] = Point(rand() % 550, rand() % 350);
    p[2] = Point(rand() % 550, rand() % 350);
    double cosValNew1, cosValNew2;
    Eigen::Vector2d v1(p[1].x, p[1].y), v2(p[2].x, p[2].y);
    Eigen::Vector2d v12 = v2 - v1, v21 = -v12;
    while (1)
    {
        p[0] = Point(rand() % 550, rand() % 350);
        Eigen::Vector2d v0(p[0].x, p[0].y);
        Eigen::Vector2d v10 = v0 - v1;
        cosValNew1 = v10.dot(v12) / (v10.norm() * v12.norm());
        if (cosValNew1 < -0.1)
            break;
    }
    while (1)
    {
        p[3] = Point(rand() % 550, rand() % 350);
        Eigen::Vector2d v3(p[3].x, p[3].y);
        Eigen::Vector2d v23 = v3 - v2;
        Eigen::Vector2d v0(p[0].x, p[0].y);
        Eigen::Vector2d v10 = v0 - v1;
        int cos=v10.dot(v23);
        cosValNew2 = v21.dot(v23) / (v21.norm() * v23.norm());
        if (cosValNew2 > 0&&cos<0)
            break;
    }
    lin[0].p_a = p[0];
    lin[0].p_b = p[1];
    lin[1].p_a = p[1];
    lin[1].p_b = p[2];
    lin[2].p_a = p[2];
    lin[2].p_b = p[3];
    lin[0].flag = lin[1].flag = 0;
    lin[2].flag = 1;
    lin[0].flag=2;

    // line(image, p[1], p[2], Scalar(0, 0, 0), 1);
    // line(image, p[0], p[1], Scalar(0, 0, 0), 1);
    // line(image, p[3], p[2], Scalar(0, 0, 0), 1);
    // imshow("begin", image);
}
double dist(node &no, linem lin)
{
    Eigen::Vector2d va(lin.p_a.x, lin.p_a.y), vb(lin.p_b.x, lin.p_b.y), vx(no.x, no.y);
    Eigen::Vector2d vab = vb - va, vax = vx - va, vbx = vx - vb;
    double cos1 = vab.dot(vax);
    double cos2 = vab.dot(vbx);
    double l;
    if (cos1 != 1 && cos1 != -1)
    {

        if (lin.flag == 0)
        {
            if (cos1 > 0 && cos2 < 0)
            {
                Eigen::Vector2d tmp;
                tmp = vax.dot(vab) / vab.norm() * vab / vab.norm();
                tmp = vax - tmp;
                l = tmp.norm();
            }
            else if (cos1 <= 0 && cos2 < 0)
            {
                l = vax.norm();
            }
            else
                l = vbx.norm();
        }
        else if (lin.flag == 1)
        {
            if (cos1 > 0)
            {
                Eigen::Vector2d tmp;
                tmp = vax.dot(vab) / vab.norm() * vab / vab.norm();
                tmp = vax - tmp;
                l = tmp.norm();
            }
            else
                l = vax.norm();
        }
        else if(lin.flag==2)
        {
            if(cos2<0)
            {
                Eigen::Vector2d tmp;
                tmp = vbx.dot(vab) / vab.norm() * vab / vab.norm();
                tmp = vbx - tmp;
                l = tmp.norm();
            }
            else
                l = vbx.norm();
        }
    }
    return l;
}
bool judgecolor(node &no, linem lin)
{
    Eigen::Vector3d va(lin.p_a.x, lin.p_a.y, 0), vb(lin.p_b.x, lin.p_b.y, 0), vx(no.x, no.y, 0);
    Eigen::Vector3d vax = vx - va, vab = vb - va;
    Eigen::Vector3d temp = vab.cross(vax);
    if (temp[2] >= 0)
        return true;
    else
        return false;
}
void mindist(node &no)
{
    double d1 = dist(no, lin[0]), d2 = dist(no, lin[1]), d3 = dist(no, lin[2]);
    double l = d1;
    bool j1 = judgecolor(no, lin[0]),j2=judgecolor(no, lin[1]),j3=judgecolor(no, lin[2]);
    no.colorflag=j1;
    if (l > d2)
    {
        no.colorflag = j2;
        l = d2;
    }
    if (l >= d3)
    {
        no.colorflag = j3;
        l = d3;
    }
    Eigen::Vector3d v1a(lin[1].p_a.x, lin[1].p_a.y, 0), v1b(lin[1].p_b.x, lin[1].p_b.y, 0),v2a(lin[2].p_a.x, lin[2].p_a.y, 0), v2b(lin[2].p_b.x, lin[2].p_b.y, 0), vx(no.x, no.y, 0);
    Eigen::Vector3d v1=v1b-v1a,v2=v2b-v2a,v2x=vx-v2a;
    double cos1=v2.dot(v1)/(v2.norm()*v1.norm());
    Eigen::Vector3d temp = v1.cross(v2);
    if(d2==d3)
    {
        if(temp[2]<0)  no.colorflag=j1||j2;
        else if(temp[2]>0) no.colorflag=j1&&j2;
    }
    no.minLength = l;
}
void all()
{
    int max = 0;
    for (int i = 0; i < 600; i++)
    {
        for (int j = 0; j < 400; j++)
        {
            node tmp;
            tmp.x = i;
            tmp.y = j;
            mindist(tmp);
            if (tmp.minLength > max)
                max = tmp.minLength;
        }
    }
    for (int i = 0; i < 600; i++)
    {
        for (int j = 0; j < 400; j++)
        {
            node tmp;
            tmp.x = i;
            tmp.y = j;
            mindist(tmp);
            if (tmp.colorflag == true)
                image.at<Vec3b>(j, i)[0] = 255 - 255 * tmp.minLength / max;
            else
                image.at<Vec3b>(j, i)[1] = 255 - 255 * tmp.minLength / max;
        }
    }
    line(image, p[0], p[1], Scalar(0, 0, 0), 1);
    line(image, p[3], p[2], Scalar(0, 0, 0), 1);
    line(image, p[1], p[2], Scalar(0, 0, 0), 1);
}
int main()
{
    do
    {

        create();
        all();
        imshow("after", image);

    } while (waitKey(0) != 'q');
    return 0;
}